home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
comm
/
fido
/
xprfts072.lzh
/
sendX.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-24
|
18KB
|
583 lines
/*
$Header: Welmat:src/Welmat/xprfts/RCS/sendX.c,v 1.2 92/11/24 23:40:44 rwm Exp Locker: rwm $
send a file with TeLink/Xmodem.
Copyright (C) 1988,1989,1990 Michael Richardson
Copyright (C) 1992 Russell McOrmond
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef RCSID
static char RCSid[]="$Id: sendX.c,v 1.2 92/11/24 23:40:44 rwm Exp Locker: rwm $";
#endif
#include <proto/all.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "xproto.h"
#include "xmodem.h"
#include "xprfts.h"
long sendXFiles(struct Vars *v)
{
long stateinfo,lasterr=OK,state=GOTACK,count=10,mdm7count=10;
char filename[256],temp[2],temp1[51];
/* send a TSYNCH to start off the transfer */
temp[0]=TSYNCH;
xpr_swrite(&v->io,temp,1);
updmsg(v,"TSYNCH!");
while(state==GOTACK) {
state=xpr_sread(&v->io,temp,1,4000000);
/* 1 char, 0 timeout, or -1 carrier drop */
if(state==0 && count--) {
temp[0]=TSYNCH;
xpr_swrite(&v->io,temp,1);
updmsg(v,"TSYNCH!");
state=GOTACK;
}
if(state==1)
if((temp[0]&0xff)==NAK) state=GOTNAK;
else if ((temp[0]&0xff)==CNAK) state=GOTCNAK;
else state=GOTACK;
}
if(!state) { /* no characters came back */
updmsg(v,"Other end didn't start transfer");
return(ERROR);
}
else if(state==-1) { /* dropped carrier */
updmsg(v,"Dropped Carrier");
return(NODCD);
}
/* clear the filename to receive the new file */
filename[0]='\0';
stateinfo=xpr_ffirst(&v->io,filename,"");
while(stateinfo) {
if (v->option_7=='N' ||
(!(v->outfiles) && (v->option_m=='Y')) || /* mail bundle */
(v->option_c=='Y' && (state==GOTCNAK))) { /* allow mdm7 skipping */
lasterr=sendXFile(v,filename);
} else {
lasterr=sendmdm7(v,filename);
}
if(lasterr==MDM7BAD && (mdm7count--));
else if(lasterr) {
updstatus(v,filename,XPRS_FAILURE);
stateinfo=NULL;
}
else {
updstatus(v,filename,XPRS_SUCCESS);
v->outfiles++;
filename[0]='\0';
lasterr=stateinfo=xpr_fnext(&v->io,stateinfo,filename,"");
}
/* wait 1 second and clear buffer */
(void)xpr_sread(&v->io,temp1,50,1000000);
/* wait for poll for more files... */
state=GOTACK;
while(state==GOTACK) {
state=xpr_sread(&v->io,temp,1,10000000);
/* 1 char, 0 timeout, or -1 carrier drop */
if(state==1)
if((temp[0]&0xff)==NAK) state=GOTNAK;
else if ((temp[0]&0xff)==CNAK) state=GOTCNAK;
else state=GOTACK;
}
if(!state) { /* no characters came back */
updmsg(v,"Other end didn't want more files");
return(ERROR);
}
else if(state==-1) { /* dropped carrier */
updmsg(v,"Dropped Carrier");
return(NODCD);
}
}
if (lasterr==OK) {
count=50;
state=0;
while(--count>0 && (state!=-1) &&
((state==0) || (((temp[0]&0xff)!=ENQ) && ((temp[0]&0xff)!=TSYNCH) &&
((temp[0]&0xff)!=ACK)))) {
if((state==0) || ((temp[0]&0xff)==NAK) || ((temp[0]&0xff)==CNAK)) {
temp1[0]=EOT;
xpr_swrite(&v->io,temp1,1);
updmsg(v,"EOTing!");
count=count-4; /* timeout/NAK's cause quicker timeout than line noise */
}
state=xpr_sread(&v->io,temp,1,2000000);
SPrintF(v->scratch,"InEOT:state = %ld, count = %ld char: %ld",state,
count,(temp[0]&0xff));
updmsg(v,v->scratch);
}
SPrintF(v->scratch,"AfterEOT:state = %ld, count = %ld char: %ld",state,
count,(temp[0]&0xff));
updmsg(v,v->scratch);
if(state==NODCD) {
lasterr=NODCD;
}
else if(state==0); /* timeout */
else if((temp[0]&0xff)==ENQ) {
/* Bark File requests */
temp1[0]=ETB;
xpr_swrite(&v->io,temp1,1);
}
else if((temp[0]&0xff)==TSYNCH);
else if((temp[0]&0xff)==ACK);
else
lasterr=ERROR;
}
return(lasterr);
}
void makeTelinkHeader(register unsigned char *buf,
char *filename,long size,long time, char mode)
{
/*mode 0=Telink, 1=Sealink, 2=Sealink(LargeNames) */
memset(buf,0,128);
/* 3 3 | File Length, least significant byte | 0 0
+-----------------------------------------------+
4 4 | File Length, second to least significant byte | 1 1
+-----------------------------------------------+
5 5 | File Length, second to most significant byte | 2 2
+-----------------------------------------------+
6 6 | File Length, most significant byte | 3 3*/
{ register char *s;
s=(char *)&size;
*buf++=s[3];
*buf++=s[2];
*buf++=s[1];
*buf++=s[0];
}
/* +-----------------------------------------------+
7 7 | Creation Time of File | 4 4
| "DOS Format" |
+-----------------------------------------------+
9 9 | Creation Date of File | 6 6
| "DOS Format" |
+-----------------------------------------------+*/
/* The above is BOGUS. We seem to be doing a SeaLink block, so
we have to do Unix timestamps... */
if(mode==0) {
register struct tm *now;
register unsigned short temp;
now=localtime(&time);
temp=(now->tm_hour<<11)|(now->tm_min<<5)|(now->tm_sec/2);
*buf++=temp&0xff;
*buf++=temp>>8;
temp=((now->tm_year-80)<<9)|(now->tm_mon<<5)|(now->tm_mday);
*buf++=temp&0xff;
*buf++=temp>>8;
}
else {
register char *s;
/* AmigaDOS Times are from 1978, Unix times from 1970. */
time=time+(60*60*24*(365*8+2));
s=(char *)&time;
*buf++=s[3];
*buf++=s[2];
*buf++=s[1];
*buf++=s[0];
}
/* 11 B | File Name | 8 8
~ 16 chars ~
| left justified blank filled |
+-----------------------------------------------+
27 1B | 00H | 24 18
+-----------------------------------------------+
28 1C | Sending Program Name | 25 19
~ 16 chars ~
| left justified Null filled |
+-----------------------------------------------+
*/
{ register int i;
/* copy filename*/
for(i=0;*filename!='\0' && i<((mode=2) ? 32 : 16);*buf++=*filename++) i++;
/* blank fill */
if (i<16) {
for(;i<16;i++) *++buf=' ';
*buf++=0;
strncpy(buf,"Welmat",15);
buf=buf+15;
} else {
for(;i<32;i++) *++buf=' ';
}
}
if(mode==0)
buf[44]=1; /* If we're doing telink, say that we're doing CRC! */
/* otherwise leave it as a 0 to indicate no compatability
with SLO */
/*
+-----------------------------------------------+
44 2B | 01H (for CRC) or 00H | 41 29
+-----------------------------------------------+
45 2C | fill | 42 2A
~ 86 bytes ~
| all zero |
+-----------------------------------------------+
*/
}
void sendXPacket(struct Vars *v,BYTE ckmode,block *lastPacket,int blocknum)
{
char *buf;
int i;
lastPacket->bl_blocknum=(blocknum&0xff);
lastPacket->bl_blockcom=(~(blocknum&0xff));
if(!ckmode) {
int ck;
lastPacket->bl_start=SYN;
buf=lastPacket->bl_contents;
ck=0;
for(i=0; i<128; i++) {
ck=ck+buf[i];
}
lastPacket->bl_check.cksum=(ck&0xff);
xpr_swrite(&v->io,&lastPacket->bl_start,132);
} else {
lastPacket->bl_start=SOH;
lastPacket->bl_check.crc=
compute_crc(lastPacket->bl_contents,128);
xpr_swrite(&v->io,&lastPacket->bl_start,133);
}
xpr_sflush(&v->io);
SPrintF(v->scratch,"Sending block #%ld %s -",blocknum,
(!ckmode ? "Check" : "CRC") );
updmsg(v,v->scratch); /* sending block # */
}
long sendXFile(struct Vars *v,char *filename)
{
struct WindowX myWindow;
block *lastPacket;
int badCount,retry;
void *workFILE; /* XPR handle on file */
char ckmode; /* a 0 for checksum, 1 for CRC */
int state;
short eof=0;
int blocknum;
short count;
if((workFILE=(void *)xpr_fopen(&v->io,filename,"r"))==NULL) {
SPrintF(v->scratch, "Couldn't open file %s",filename);
updmsg(v,v->scratch);
return(ERROR);
}
else { /* We could open the file */
(void) AllocWindowX(&myWindow); /* TODO: Do checks for not allocated */
/*
| XS0 | WaitTeLnk| 1 over 40-60 seconds | report sender timeout | exit|
| | | 2 over 2 tries | note TeLink block failed| XS1 |
| | | 3 NAK or "C" received | send TeLink, incr tries | XS0 |
| | | 4 ACK received | TeLink ok, set crc/cksm | XS2 |
really like this:
XS0a 1 timeout (40-60 sec) exit
2 NAK or "C" | send TeLink block XS0b
XS0b 1 timeout (40-60 sec) exit
2 NAK or "C" | send TeLink block XS0c
3 ACK | TeLink ok, set crc/cksm XS2
XS0c 1 timeout (40-6- sec) exit
2 NAK or "C" | note TeLink block failed fail?
3 ACK | TeLink ok XS2 */
if((lastPacket=(block *)RemHead(&myWindow.wx_freeblocks))==NULL) {
updmsg(v,"Fully Tilted Head");
FreeWindowX(&myWindow);
xpr_fclose(&v->io,workFILE);
return(ERROR);
}
retry=9;
state=GOTNAK;
if (!(v->outfiles) || (v->option_f=='Y')) {
while((state!=GOTACK) && (retry--)) {
char temp[2];
ckmode=((v->option_o=='T') ? 0 :
(retry<5 && (v->option_o!='S')) ? 0 :
(v->option_b=='Y') ? 2 : 1);
makeTelinkHeader(lastPacket->bl_contents,filename,
xpr_finfo(&v->io,filename,1),
0,
ckmode);
sendXPacket(v,ckmode,lastPacket,0);
state=xpr_sread(&v->io,temp,1,5000000);
if(state==NODCD) {
FreeWindowX(&myWindow);
xpr_fclose(&v->io,workFILE);
return(NODCD);
}
if(state && (temp[0]==ACK)) state=GOTACK;
}
SPrintF(v->scratch,"retry %ld ckmode %ld Filename:%s",retry,ckmode,
filename);
updmsg(v,v->scratch);
}
if(state!=GOTACK) { /* Header Block Failed */
updmsg(v,"Header block failed!");
if(!(v->outfiles) && (v->option_m=='Y')) {
/* It's ok, it is the mail bundle */
goto send_file;
}
else if(v->option_7=='Y') {
goto send_file; /* We relayed the file name another way. */
}
else { /* Too, bad. I don't do UNKNOWN.$$$ */
FreeWindowX(&myWindow);
xpr_fclose(&v->io,workFILE);
return(ERROR);
}
}
/* header was successfull! */
SPrintF(v->scratch,"%s header block sent!",
(ckmode ? "SeaLink" : "Telink"));
updmsg(v,v->scratch);
send_file:
blocknum=1;
badCount=0;
xpr_sflush(&v->io);
while(!eof) {
{ short i;
if((i=xpr_fread(&v->io,lastPacket->bl_contents, 1,128,workFILE))!=128) {
for(;i<128; i++) {
lastPacket->bl_contents[i]=SUB;
}
eof=1;
}
}
/*
| XS2 | SendBlock| 1 more data available | send next data block | XS3 |
| | | | as checksum or crc | |
| | | 2 last block has gone | send EOT | XS4 |
| XS3 | WaitACK | 1 10 retries or 1 minute| report send failed | exit|
| | | 2 ACK received | | XS2 |
| | | 3 NAK (or C if 1st blk) | resend last block | XS3 |
| XS4 | WaitEnd | 1 10 retries or 1 minute| report send failed | exit|
| | | 2 ACK received | report send successful | exit|
| | | 3 NAK received | resend EOT | XS4 |
*/
state=GOTNAK;
count=0;
while(state==GOTNAK) {
char temp[2];
xpr_sflush(&v->io); /* temporary for non-sealink sends */
sendXPacket(v,1,lastPacket,blocknum);
state=0;
while (state>-1) {
state=xpr_sread(&v->io,temp,1,4000000);
if(state==-1) {
updmsg(v,"Lost carrier!");
xpr_fclose(&v->io,workFILE);
FreeWindowX(&myWindow);
return(NODCD);
}
if(state==1)
if((temp[0]&0xff)==ACK) {
state=GOTACK;
updmsg(v,"R:ACK");
} else if ((temp[0]&0xff)==NAK) {
updmsg(v,"R:NAK");
badCount++;
state=GOTNAK;
} else {
SPrintF(v->scratch,"R:Junk(%ld)\n",temp[0]&0xff);
updmsg(v,v->scratch);
}
else {
state=GOTNAK;
updmsg(v,"TIME");
badCount++;
}
if((state==GOTNAK) && count++>10) {
updmsg(v,"Too many retries. Line bad.");
xpr_fclose(&v->io,workFILE);
FreeWindowX(&myWindow);
return(ERROR);
}
}
}
blocknum++;
}
xpr_fclose(&v->io,workFILE);
count=0;
state=TIMEOUT;
while((state==GOTNAK) || (state==TIMEOUT)) {
char temp[2];
if(state==TIMEOUT) {
temp[0]=EOT;
xpr_swrite(&v->io,temp,1);
updmsg(v,"EOF/EOT");
}
state=xpr_sread(&v->io,temp,1,2000000);
SPrintF(v->scratch,"state:%ld, c:%ld",state,temp[0]&0xff);
updmsg(v,v->scratch);
if(state==-1) return(NODCD);
if(state && ((temp[0]&0xff)==ACK)) state=GOTACK;
else if(state) state=GOTNAK;
else {
state=TIMEOUT;
if(count++>9) {
updmsg(v,"Too many retries. Can't end transfer.");
FreeWindowX(&myWindow);
return(ERROR);
}
}
}
end:
FreeWindowX(&myWindow);
return(OK);
}
}
long sendmdm7(struct Vars *v,char *filename)
{
long i,state;
UBYTE mdm7name[16],*tempf,cksum,c,temp[2],temp1[2];
/* get basename */
for(tempf=filename+strlen(filename);
tempf!=filename && *(tempf-1)!='/' && *(tempf-1)!=':';
tempf--);
#ifdef KDEBUG
KPrintF("Filename: '%s' BaseName '%s'\n",filename,tempf);
#endif
for(i=0; i<11; i++) mdm7name[i]=' ';
mdm7name[11]='\0';
for(i=0; i<11 && *tempf!='\0'; i++) {
if(*tempf=='.') {
i=7;
}
else {
mdm7name[i]=toupper(*tempf);
}
tempf++;
}
cksum=0;
for(i=0; i<11; i++ ) {
cksum+=mdm7name[i];
}
cksum+=SUB;
cksum=cksum&0xff;
mdm7name[11]='\0';
/*
|-----+----------+-------------------------+-------------------------+-----|
| MS0 | WaitNak | 1 20 retries or 1 minute| filename send failed | exit|
| | | 2 NAK received | send ACK & 1st ch of fn | MS1 |
|-----+----------+-------------------------+-------------------------+-----|
| MS1 | WaitChAck| 1 ACK rcd, fname done | send SUB = 1AH | MS2 |
| | | 2 ACK rcd, fname ~done | send next ch of fname | MS1 |
| | | 3 other char or 1 sec | send "u", incr retry cnt| MS0 |
|-----+----------+-------------------------+-------------------------+-----|
*/
xpr_sflush(&v->io);
temp1[0]=ACK;
xpr_swrite(&v->io,temp1,1);
updmsg(v,"MDM7 filename send");
for(i=0; i<11; i++) {
xpr_swrite(&v->io,&mdm7name[i],1);
state=xpr_sread(&v->io,temp,1,5000000);
if(state==1 && (temp[0]&0xff==CAN)) {
temp1[0]=ACK;
xpr_swrite(&v->io,temp1,1);
return(GOTEOT);
}
else if(state!=1 || ((temp[0]&0xff) != ACK))
break;
}
#ifdef KDEBUG
KPrintF("Sread1: %ld c=%ld\n",state,temp[0]&0xff);
#endif
if((state==1) && ((temp[0]&0xff)==ACK)) {
/*
| MS2 | WaitCksm | 1 cksum recd and ok | send ACK, report fn ok | exit|
| | | 2 cksum recd but bad | send "u", incr retry cnt| MS0 |
| | | 3 no cksum in 1 sec | send "u", incr retry cnt| MS0 |
*/
temp1[0]=SUB;
xpr_swrite(&v->io,temp1,1);
state=xpr_sread(&v->io,temp,1,3000000);
#ifdef KDEBUG
KPrintF("Sread2: %ld c=%ld\n",state,temp[0]&0xff);
#endif
if(state==1)
if((c=temp[0]&0xff)==cksum) {
temp1[0]=ACK;
xpr_swrite(&v->io,temp1,1);
return(sendXFile(v,filename));
} else {
SPrintF(v->scratch,"Modem7 checksum failed: %ld vs %ld",c,cksum);
updmsg(v,v->scratch);
}
else
updmsg(v,"Time/DCD");
}
temp1[0]='u';
xpr_swrite(&v->io,temp1,1);
updmsg(v,"Modem7 Filename send failed");
return(MDM7BAD);
}